package de.wesemann.jdedun.implementation;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;

import de.wesemann.jdedun.entities.Count;

public class AbstractResource{

    private Logger logger = LoggerFactory.getLogger(AbstractResource.class);
    private static final String API_KEY = "NkEQIbCD9tpkhS5ftO"; // implement your own api key
    private static final String API_KEY_PREFIX = "api_key=";
    private static final Gson GSON = new Gson();
    private static final String urlPrefix = "http://www.apileipzig.de/api/v1/";
    private static final String OFFSET = "offset=";
    private static final String COUNT = "count";
    private static final String LIMIT = "limit=";
    private String urlStub;

    public AbstractResource(String urlStub) {
	this.urlStub = urlStub;
    }

    /**
     * get all resources from the urlStub
     * 
     * @param <T>
     *            The pojo which inherents the json data as objectdata?
     * @param classOfT
     *            The class of the pojo
     * @return the class of the pojo
     */
    public <T> T getAll(Class<T> classOfT) {
	URL url = null;
	T all = null;
	StringBuilder urlBuilder = new StringBuilder(urlPrefix);
	urlBuilder.append(urlStub).append("?").append(API_KEY_PREFIX)
		.append(API_KEY);
	try {
	    url = new URL(urlBuilder.toString());
	    logger.debug("created url: " + url.toString());

	    all = jsonToObject(classOfT, url);
	} catch (MalformedURLException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} catch (IOException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}

	return (T) all;
    }

    /**
     * search in the resources with this help. <br>
     * with the key q it is possible to do an fulltext search. <br>
     * else the keys should be available in the resource of the apileipzig
     * 
     * @param <T>
     *            the class which represents the json object
     * @param searchTupel
     *            the tupel
     * @param classOfT
     *            the class (normaly the pojo) which represents the json object
     * @return the pojo class with the json elements in it
     */
    public <T> T search(Map<String, String> searchTupel, Class<T> classOfT) {
	URL url = null;
	T searched = null;
	StringBuilder urlBuilder = new StringBuilder(urlPrefix);
	urlBuilder.append(urlStub).append("/").append("search").append("?")
		.append(API_KEY_PREFIX).append(API_KEY);
	for (String key : searchTupel.keySet()) {
	    urlBuilder.append("&").append(key).append("=")
		    .append(searchTupel.get(key));
	}
	try {
	    url = new URL(urlBuilder.toString());
	    logger.debug("created url: " + url.toString());

	    searched = jsonToObject(classOfT, url);
	} catch (MalformedURLException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} catch (IOException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}

	return (T) searched;
    }

    /**
     * 
     * @return the number of resources
     */
    public int count() {
	URL url = null;
	StringBuilder urlBuilder = new StringBuilder(urlPrefix);
	urlBuilder.append(urlStub).append("/").append(COUNT).append("?")
		.append(API_KEY_PREFIX).append(API_KEY);
	try {

	    url = new URL(urlBuilder.toString());
	} catch (MalformedURLException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}
	logger.debug("created url: " + url.toString());
	Count count = null;
	try {
	    count = jsonToObject(Count.class, url);
	} catch (IOException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}

	return count.getCount();
    }

    /**
     * used to scroll over the resources
     * 
     * @param <T>
     *            the class which represents the json object
     * @param offset
     *            on which element it should begin
     * @param limit
     *            the resources per page
     * @param classOfT
     *            the class (normaly the pojo) which represents the json object
     * @return the pojo class with the json elements in it
     */
    public <T> T get(int limit, int offset, Class<T> classOfT) {
	URL url = null;
	T searchedBranche = null;
	StringBuilder urlBuilder = new StringBuilder(urlPrefix);
	urlBuilder.append(urlStub).append("?").append(API_KEY_PREFIX)
		.append(API_KEY).append("&").append(LIMIT).append(limit)
		.append("&").append(OFFSET).append(offset);
	try {
	    url = new URL(urlBuilder.toString());
	    logger.debug("created url: " + url.toString());

	    searchedBranche = jsonToObject(classOfT, url);
	} catch (MalformedURLException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} catch (IOException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}
	return (T) searchedBranche;
    }

    /**
     * 
     * @param <T>
     * @param classOfT
     * @param url
     * @return
     * @throws IOException
     */
    public final <T> T jsonToObject(Class<T> classOfT, URL url)
	    throws IOException {

	InputStreamReader isr = new InputStreamReader(url.openStream());
	T object = null;
	try {
	    object = GSON.fromJson(isr, classOfT);
	} catch (JsonSyntaxException je) {
	    logger.error("The Json doesnt confirm with the class {}",
		    classOfT.getCanonicalName());
	    logger.error("{}", je.toString());
	}
	return (T) object;

    }

}
